package com.cy.pj.sys.service.impl;

import com.cy.pj.common.annotation.RequiredLog;
import com.cy.pj.common.exception.ServiceException;
import com.cy.pj.common.util.ShiroUtil;
import com.cy.pj.sys.dao.SysUserDao;
import com.cy.pj.sys.dao.SysUserRoleDao;
import com.cy.pj.sys.pojo.SysUser;
import com.cy.pj.sys.service.SysUserService;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.crypto.hash.SimpleHash;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.UUID;

@Service
public class SysUserServiceImpl implements SysUserService {
    @Autowired
    private SysUserDao sysUserDao;
    @Autowired
    private SysUserRoleDao sysUserRoleDao;

    /**
     * 这里设置了权限管理,分页会出现问题,因为执行这个方法会执行两个sql查询语句
     * 分页保存了权限查询的语句,导致查询出来的结果是权限信息,
     * 第一我们可以把分页功能挪到Impl层进行实现,但这样我们需要改动很多代码
     * 第二
     * @param entity
     * @return
     */
   // @RequiresPermissions("sys:user:view")
    @Override
    @RequiredLog("日志分页查询")
    public List<SysUser> findUsers(SysUser entity) {
        return sysUserDao.selectUsers(entity);
    }


  //  @RequiresPermissions("sys:user:view")
    @Transactional
    @Override
    public SysUser findById(Integer id) {
        //更新用户自身信息
        SysUser user = sysUserDao.selectById(id);
        if (user==null)
            throw new ServiceException("此用户可能已经不存在");
        //更新用户和角色关系数据
        List<Integer> roleIds = sysUserRoleDao.selectRoleIdsByUserId(id);
        user.setRoleIds(roleIds);
        return user;

    }

    @Transactional(timeout = 60)
    @Override
    public int saveUser(SysUser entity) {
        //产生一个随机字符串作为加密盐使用
        String salt = UUID.randomUUID().toString();
        //对密码进行MD5盐值加密(MD5 特点:不可逆,相同内容加密结果也相同)
        SimpleHash sh = new SimpleHash("MD5",entity.getPassword(),salt,1);
        String hashedPassword = sh.toHex();//将加密结果转换为16进制
        entity.setSalt(salt);
        entity.setPassword(hashedPassword);
        int rows = sysUserDao.insertUser(entity);
        sysUserRoleDao.insertUserRoles(entity.getId(),entity.getRoleIds());
        return rows;
    }
    @Transactional
    @Override
    public int updateUser(SysUser entity) {
        //开启事务
        //1.参数校验
        //2.更新用户自身信息
        int rows = sysUserDao.updateUser(entity);
        if (rows==0)
            throw  new ServiceException("纪录可能已经不存在");
        //3.更新用户和角色关系数据
        sysUserRoleDao.deleteByUserId(entity.getId());
        sysUserRoleDao.insertUserRoles(entity.getId(),entity.getRoleIds());
        return rows;
    }

    /**
     * @Transactional 描述方法时,此方法为一个事务切入点方法
     * @RequiresPermissions 描述方法时为一个授权切入点方法,我们在
     * 访问此方法时就需要授权,有权限可以访问,没有权限则抛出异常,
     * 那如何判定用户有没有访问此方法的权限呢?当我们在方法时,shiro框架底层
     * 会获取此方法上的@RequiresPermissions注解,进而取到注解中的权限标识,然后
     * 会调用subject对象的checkRermissions(权限标识) 方法检测用户是否有权限.
     *
     *
     * 这个方法的权限检测调用流程分析?
     * controller->AopProxy->AuthorizingMethodInterceptor-->subject.checkPermission
     * ->SecurityManager->CheckPermission
     *
     * subject -> SecurityManager - Authorize -->Realm
     * @param id
     * @param valid
     * @return
     */
   // @RequiresPermissions("sys:user:update")
    @Override
    public int validById(Integer id, Integer valid) {
        //获取用户权限Set<String> permissions
        //获取此方法上的权限表示sys:user:update
        //判定用户的权限中是否包含方法上的权限表示 flag=  permissions.contains(sys:user:update)
        //if(flag){}else{}
//        String modifiedUser="admin";//后续是登录用户
//        int rows = sysUserDao.validById(id,valid,modifiedUser);
        SysUser user = ShiroUtil.getUser();
        String modifiedUser = user.getUsername();
        int rows = sysUserDao.validById(id,valid,modifiedUser);
        if (rows==0)
            throw new ServiceException("纪录可能已经不存在");
        return rows;
    }

    @Override
    public int updatePassword(String sourcePassword, String newPassword, String confirmPassword) {
       if (sourcePassword==null||"".equals(sourcePassword)){
           throw new IllegalArgumentException("原密码不能为空");
       }
       if (newPassword==null||"".equals(newPassword)){
           throw  new IllegalArgumentException("新密码不能为空");
       }
       if (!newPassword.equals(confirmPassword)){
           throw new IllegalArgumentException("两次输入的密码不一致");
       }

       //获取登录用户,并判定登录用户的密码和用户输入的原密码是否一致
       SysUser user = (SysUser) SecurityUtils.getSubject().getPrincipal();
       SimpleHash sh  = new SimpleHash("MD5",sourcePassword,user.getSalt(),1);
       if (!user.getPassword().equals(sh.toHex()))//MD5加密,相同内容加密结果也相同
           throw new IllegalArgumentException("原密码不正确");
       String newSalt = UUID.randomUUID().toString();//生成盐
       sh = new SimpleHash("MD5",newPassword,newSalt,1);
       String newHashedPassword = sh.toHex();//已加密的密码
        //3/更新用户密码
        int rows = sysUserDao.updatePassword(newHashedPassword,newSalt,user.getId());
        return rows;
    }


}
